package net.oschina.thrift.client.support.pool.factory;

import net.oschina.thrift.client.support.config.TSConfig;
import net.oschina.thrift.client.support.pool.PooledTServiceClient;
import net.oschina.thrift.client.support.pool.TSConfigProvider;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.thrift.TServiceClient;
import org.apache.thrift.TServiceClientFactory;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author dw_xiajiqiu1
 * @time 2017/6/19 11:08
 */
public abstract class AbstractTSocketTClientPooledObjectFactory extends BasePooledObjectFactory<PooledTServiceClient> implements TClientPooledObjectFactory {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    /** 配置提供者 */
    protected TSConfigProvider configProvider;

    /** 客户端的工厂类 */
    protected TServiceClientFactory<TServiceClient> clientFactory;

    @Override
    public TSConfigProvider getConfigProvider() {
        return configProvider;
    }

    @Override
    public void setConfigProvider(TSConfigProvider configProvider) {
        this.configProvider = configProvider;
    }

    @Override
    public TServiceClientFactory<TServiceClient> getClientFactory() {
        return clientFactory;
    }

    @Override
    public void setClientFactory(TServiceClientFactory<TServiceClient> clientFactory) {
        this.clientFactory = clientFactory;
    }

    /**
     * 创建一个对象
     *
     * @return
     * @throws Exception
     */
    @Override
    public PooledTServiceClient create() throws Exception {
        // 选择一个服务器配置
        TSConfig config = this.configProvider.select();

        logger.info("准备创建 PooledTServiceClient： " + TSConfig.serialize(config));

        TSocket socket = new TSocket(config.getHost(), config.getPort());

        if (config.getTimeout() > 0) {
            socket.setTimeout(config.getTimeout());
        }

        TTransport transport = wrapTSocketTransport(config, socket);

        TProtocol protocol = buildProtocol(config, transport, socket);

        transport.open();

        TServiceClient client = this.clientFactory.getClient(protocol);

        PooledTServiceClient pooledTServiceClient = new PooledTServiceClient(client, transport, config);
        logger.info("成功创建一个新的 PooledTServiceClient： " + pooledTServiceClient);
        return pooledTServiceClient;
    }

    protected abstract TProtocol buildProtocol(TSConfig config, TTransport transport, TSocket socket);

    protected TTransport wrapTSocketTransport(TSConfig config, TSocket socket) {
        return socket;
    }

    @Override
    public PooledObject<PooledTServiceClient> wrap(PooledTServiceClient client) {
        return new DefaultPooledObject<PooledTServiceClient>(client);
    }

    /**
     * 从连接池中删除该对象
     *
     * @param pooledObject 要删除的对象
     * @throws Exception
     */
    @Override
    public void destroyObject(PooledObject<PooledTServiceClient> pooledObject) throws Exception {
        super.destroyObject(pooledObject);
        PooledTServiceClient client = pooledObject.getObject();
        logger.info("销毁一个 PooledTServiceClient： " + client);
        // 调用出错的时候废弃
        client.discard();
        TTransport transport = client.getTransport();
        if (transport != null) {
            transport.close();
        }
    }

    @Override
    public boolean validateObject(PooledObject<PooledTServiceClient> pooledObject) {
        logger.info("Validate 一个 TServiceClient 状态： " + pooledObject.getObject());
        PooledTServiceClient serviceClient = pooledObject.getObject();
        if (serviceClient.isDiscard()) {
            return false;
        }
        TTransport transport = serviceClient.getServiceClient().getInputProtocol().getTransport();
        boolean commonValidate = transport.isOpen() && serviceClient.getServiceClient().getOutputProtocol().getTransport().isOpen();
        if (commonValidate) {
            return customValidate(pooledObject);
        }
        return false;
    }

    /**
     * 自定义检测逻辑，比如实现ping方法，用于继承
     *
     * @param pooledObject 连接池对象
     * @return
     */
    protected boolean customValidate(PooledObject<PooledTServiceClient> pooledObject) {
        return true;
    }
}
